package com.protocols.sctp.m3ua.sccp.tcap;
import java.rmi.*;

import java.rmi.registry.*;

import java.rmi.server.*;
import java.util.Arrays;
import java.util.Properties;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.*;

import com.Main.MyServiceInterface;
import com.Main.ReceiveMessageInterface;
import com.protocols.GeneralProtocolData;
import com.protocols.ProtoOperations;
import com.protocols.sctp.SctpHandlerInterface;
import com.protocols.sctp.m3ua.M3uaHandlerInterface;
import com.protocols.sctp.m3ua.M3uaPayLoadData;
import com.protocols.sctp.m3ua.sccp.SccpHandler;
import com.protocols.sctp.m3ua.sccp.SccpHandlerInterface;
import com.protocols.sctp.m3ua.sccp.SccpUnitDataMsg;
import com.protocols.sctp.m3ua.sccp.tcap.camel.*;
import com.protocols.sctp.m3ua.sccp.tcap.map.MapHandlerInterface;
import com.protocols.sctp.m3ua.sccp.tcap.map.MapInvokeUnstructuredSSNotify;
import com.protocols.sctp.m3ua.sccp.tcap.map.MapInvokeUnstructuredSSRequest;


 

public class TcapHandler extends java.rmi.server.UnicastRemoteObject implements TcapHandlerInterface,MyServiceInterface{

	// Configuring the Logger
	
	SccpHandlerInterface SccpHandler=null;
	private CamelHandlerInterface CamelHandler=null;
	private MapHandlerInterface MapHandler=null;
	private long TransactionID=1;
	private Registry Registry;  
    Logger Log = Logger.getLogger(this.getClass().getName());
    Boolean logInfoEnabled=false;
    
 // Default Configuration
    int layerServiceport=9001;
	String tcaphandlerurl= "TcapHandler";		
	String camelhandlerurl= "CamelHandler";
	private String maphandlerurl= "MapHandler";
	String sccphandlerurl= "SccpHandler";
	int ConnRetry=3000;		
	String logfile= "var/log/tcap.log";
	Level loglevel= Level.OFF;
    
    public TcapHandler() throws RemoteException {
    	super();
		

        
    }

  
	
	public void initialise() throws Exception{	
		
		Properties properties=null;
		try{			
			properties = new java.util.Properties();
			properties.load( new FileInputStream("General.conf"));
		}catch( IOException e){
			System.out.println("Couldn't locate the Config File");				
			System.exit(0);
		}			
		logfile= properties.getProperty("tcap.log.filepath");
		loglevel= Level.parse(properties.getProperty("tcap.log.level"));
		
		FileHandler filehandler=null;
		try{
			filehandler= new FileHandler(logfile,true);
			filehandler.setFormatter(new SimpleFormatter());
			Log.addHandler(filehandler);
			Log.setLevel(loglevel);				
		}catch( IOException e){
			System.out.println("Issue Opening the Log File. Setting the Log Level to 'OFF'");	
			Log.setLevel(Level.OFF);	
		}
		
		logInfoEnabled=Log.isLoggable(Level.INFO);	
		
		layerServiceport=Integer.valueOf(properties.getProperty("layerservice.port"));
		tcaphandlerurl= properties.getProperty("tcap.layerservice.url");
		camelhandlerurl= properties.getProperty("camel.layerservice.url");
		maphandlerurl= properties.getProperty("map.layerservice.url");
		sccphandlerurl= properties.getProperty("sccp.layerservice.url");
		ConnRetry=Integer.valueOf(properties.getProperty("connectionretryinterval"));		
		
			
		try{
			Registry = LocateRegistry.createRegistry( layerServiceport );
			if(logInfoEnabled)Log.info("Created Registry on Port:"+layerServiceport);
		}catch(RemoteException e){
			Registry = LocateRegistry.getRegistry( layerServiceport );	
			if(logInfoEnabled)Log.info("Obtained Registry from Port:"+layerServiceport);
		}
			
		
		Registry.rebind(tcaphandlerurl, this);			
		if(logInfoEnabled)Log.info("Bound Tcap Handler on Url:"+tcaphandlerurl);
		
		
	}


	public void establishSccpConnection() throws Exception
	{
		Boolean retry=true;
		while(retry)
		{
			try{
				SccpHandler=(SccpHandlerInterface)(Registry.lookup(sccphandlerurl));
				retry=false;
			}catch(Exception e){	
				Log.severe("Couldn't Obtained the SccpHandler Instance. Retry in "+ConnRetry+" Secs.");
				Thread.sleep(ConnRetry);
			}
		}
		if(logInfoEnabled)Log.info("Obtained SccpHandler Instance");
	}
	
	
	public void establishCamelConnection() throws Exception
	{
		Boolean retry=true;
		while(retry)
		{
			try{
				CamelHandler=(CamelHandlerInterface)(Registry.lookup(camelhandlerurl));
				retry=false;
			}catch(Exception e){	
				Log.severe("Couldn't Obtained the CamelHandler. Retry in "+ConnRetry+" Secs.");
				Thread.sleep(ConnRetry);
			}
		}				
		if(logInfoEnabled)Log.info("Obtained CamelHandler Instance");
		
	}
	
	public void establishMapConnection() throws Exception
	{
		Boolean retry=true;
		while(retry)
		{
			try{
				MapHandler=(MapHandlerInterface)(Registry.lookup(maphandlerurl));
				retry=false;
			}catch(Exception e){	
				Log.severe("Couldn't Obtained the MapHandler. Retry in "+ConnRetry+" Secs.");
				Thread.sleep(ConnRetry);
			}
		}				
		if(logInfoEnabled)Log.info("Obtained MapHandler Instance");
		
	}


	@Override
	public GeneralProtocolData sccpToTcap(long sessionid, byte input [], int OPC, int DPC, String OGT, String DGT, int SSN) throws RemoteException{
		try{
			if ((input[1]&0xff)==0x62 ){	 // TCAP Begin
				if(logInfoEnabled)Log.info(sessionid+":Received TCAP Begin");
				TcapBegin tcapdata = new TcapBegin();
				byte [] payload =tcapdata.decode(input);	
				
				if (SSN==146){// Camel
					GeneralProtocolData camel = CamelHandler.tacpToCamel(sessionid, payload,OPC, DPC,  OGT, DGT, tcapdata.getSourceTransactionID(), getNextTransactionID());
				}
				else if (SSN==147){	//GSM Map
					MapHandler.tcapToMap(sessionid, payload, tcapdata.getSingleANSEncoding(), OPC, DPC, OGT, DGT, tcapdata.getSourceTransactionID(), getNextTransactionID());
				}
				
			}
			else if ((input[1]&0xff)==0x65 ){	 // TCAP Continue
				if(logInfoEnabled)Log.info(sessionid+":Received TCAP Continue OGT:"+OGT+" DGT:"+DGT);
				TcapContinue tcapcontinue = new TcapContinue();
				byte [] payload =tcapcontinue.decode(input);	
				
				if (SSN==146){// Camel
					CamelHandler.tacpToCamel(sessionid, payload,OPC, DPC,  OGT, DGT, tcapcontinue.getSourceTransactionID(), tcapcontinue.getDestinationTransactionID());
					
				}
				else if (SSN==147){// GSM Map
					MapHandler.tcapToMap(sessionid, payload,null,OPC, DPC,  OGT, DGT, tcapcontinue.getSourceTransactionID(), tcapcontinue.getDestinationTransactionID());
					
				}
			}
			else if ((input[1]&0xff)==0x64){	 // TCAP End
				if(logInfoEnabled)Log.info(sessionid+":Received TCAP End OGT:"+OGT+" DGT:"+DGT);
				TcapEnd tcapend = new TcapEnd();
				byte [] payload =tcapend.decode(input);	
				
				if (SSN==146){// Camel
					GeneralProtocolData camel = CamelHandler.tacpToCamel(sessionid, payload,OPC, DPC,  OGT, DGT, 0, tcapend.getDestinationTransactionID());
				
				}
				else if (SSN==147){	//GSM Map
					MapHandler.tcapToMap(sessionid, payload, null, OPC, DPC, OGT, DGT, 0, tcapend.getDestinationTransactionID());
					
				}
			}
			else if ((input[1]&0xff)==0x67){	 // TCAP Abort
				if(logInfoEnabled)Log.info(sessionid+":Received TCAP Abort OGT:"+OGT+" DGT:"+DGT);
				TcapAbort tcapAbort = new TcapAbort();
				byte [] payload =tcapAbort.decode(input);	
				
				if (SSN==146){// Camel
					GeneralProtocolData camel = CamelHandler.tacpAbort(sessionid, OPC, DPC,  OGT, DGT, 0, tcapAbort.getDestinationTransactionID());
					
				}
				else if (SSN==147){// MAP
					MapHandler.tcapToMap(sessionid, payload, null, OPC, DPC, OGT, DGT, 0, tcapAbort.getDestinationTransactionID());
					
				}
			}
		}catch(Exception e){
			Log.warning(sessionid+":Exception Occured :" +e.getClass().getSimpleName()+":"+ Arrays.toString(e.getStackTrace()));

		}
		return null;
	}




	@Override
	public void camelToTcap(long sessionid,GeneralProtocolData cameldata,String OGT, String DGT, long OrigTransactionID, long DestTransactionID) throws RemoteException {
		
		try{
			TcapBegin tcapbegin = new TcapBegin();		
			tcapbegin.setSourceTransactionID(OrigTransactionID);
			
			TcapContinue tcapcontinue = new TcapContinue();		
			tcapcontinue.setSourceTransactionID(OrigTransactionID);
			tcapcontinue.setDestinationTransactionID(DestTransactionID);
			
			String CamelMsgType=cameldata.getClass().getSimpleName();
			
			switch (CamelMsgType) {
			case "CamelInitialDP":
			{
				//TCAP Begin
				if(logInfoEnabled)Log.info(sessionid+":Received  CamelInitialDP");	
				tcapbegin.setObjectID((new byte[] {00,0x11,(byte)0x86,0x05,01,01,01}));
				tcapbegin.setApplicationContext(0x04000001003201L);
				tcapbegin.setProtocolVersion(0x0780);
				
				CamelInitialDP initialdp = (CamelInitialDP)cameldata;
				tcapbegin.ComponentPortion.addElement(initialdp.getRootComponent());
				if(logInfoEnabled)Log.info(sessionid+":Sending INITIAL DP with TCAP Begin Stream");
				SccpHandler.tcapToSccp(sessionid, tcapbegin, OGT, DGT, 146, 146);
				
				break;
			}
			case "CamelApplyChargingReport":
			{
				//TCAP Continue
				if(logInfoEnabled)Log.info(sessionid+":Received  CamelApplyChargingReport");	
				
				
				CamelApplyChargingReport applyChargingReport = (CamelApplyChargingReport)cameldata;
				tcapcontinue.ComponentPortion.addElement(applyChargingReport.getRootComponent());
				if(logInfoEnabled)Log.info(sessionid+":Sending CamelApplyChargingReport with TCAP Continue Stream");
				SccpHandler.tcapToSccp(sessionid, tcapcontinue, OGT, DGT, 146, 146);
				
				break;
			}
			case "CamelEventReportBCSM":
			{
				//TCAP Continue
				if(logInfoEnabled)Log.info(sessionid+":Received  CamelEventReportBCSM");	
				
				
				CamelEventReportBCSM eventReportBCSM = (CamelEventReportBCSM)cameldata;
				tcapcontinue.ComponentPortion.addElement(eventReportBCSM.getRootComponent());
				if(logInfoEnabled)Log.info(sessionid+":Sending CamelEventReportBCSM with TCAP Continue Stream");
				SccpHandler.tcapToSccp(sessionid, tcapcontinue, OGT, DGT, 146, 146);
				
				break;
			}
			case "CamelReturnResultLast":
			{
				//TCAP Continue
				if(logInfoEnabled)Log.info(sessionid+":Received  CamelReturnResultLast");	
				CamelReturnResultLast returnResultLast = (CamelReturnResultLast)cameldata;
				tcapcontinue.ComponentPortion.addElement(returnResultLast.getRootComponent());
				if(logInfoEnabled)Log.info(sessionid+":Sending CamelReturnResultLast with TCAP Continue Stream");
				SccpHandler.tcapToSccp(sessionid, tcapcontinue, OGT, DGT, 146, 146);
				
				break;
			}
			case "CamelReturnResultNotLast":
			{
				//TCAP Continue
				if(logInfoEnabled)Log.info(sessionid+":Received  CamelReturnResultNotLast");	
				
				CamelReturnResultNotLast returnResultNotLast = (CamelReturnResultNotLast)cameldata;
				tcapcontinue.ComponentPortion.addElement(returnResultNotLast.getRootComponent());
				if(logInfoEnabled)Log.info(sessionid+":Sending CamelReturnResultNotLast with TCAP Continue Stream");
				SccpHandler.tcapToSccp(sessionid, tcapcontinue, OGT, DGT, 146, 146);
				
				break;
			}
			case "CamelRequestReportBCSMEvent":
			{
				//TCAP Continue
				if(logInfoEnabled)Log.info(sessionid+":Received  CamelRequestReportBCSMEvent");	
				tcapcontinue.setObjectID((new byte[] {00,0x11,(byte)0x86,0x05,01,01,01}));
				tcapcontinue.setApplicationContext(0x04000001003201L);
				tcapcontinue.setProtocolVersion(0x0780);				
				tcapcontinue.setResult(0);
				tcapcontinue.setDialogServiceUser(0);			
				
				
				CamelRequestReportBCSMEvent requestReportBCSMEvent = (CamelRequestReportBCSMEvent)cameldata;
				tcapcontinue.ComponentPortion.addElement(requestReportBCSMEvent.getRootComponent());
				if(logInfoEnabled)Log.info(sessionid+":Sending CamelRequestReportBCSMEvent with TCAP Continue Stream");
				SccpHandler.tcapToSccp(sessionid, tcapcontinue, OGT, DGT, 146, 146);
				
				break;
			}
			case "CamelConnect":
			{
				//TCAP Continue
				
				tcapcontinue.setObjectID((new byte[] {00,0x11,(byte)0x86,0x05,01,01,01}));
				tcapcontinue.setApplicationContext(0x04000001003201L);
				tcapcontinue.setProtocolVersion(0x0780);				
				tcapcontinue.setResult(0);
				tcapcontinue.setDialogServiceUser(0);			
				
				CamelConnect camelConnect = (CamelConnect)cameldata;
				tcapcontinue.ComponentPortion.addElement(camelConnect.getRootComponent());
				if(logInfoEnabled)Log.info(sessionid+":Sending camelConnect with TCAP Continue Stream");
				SccpHandler.tcapToSccp(sessionid, tcapcontinue, OGT, DGT, 146, 146);
				
				break;
			}
			case "CamelContinue":
			{
				//TCAP Continue
				
				if(logInfoEnabled)Log.info(sessionid+":Received  CamelContinue");	
				
				tcapcontinue.setObjectID((new byte[] {00,0x11,(byte)0x86,0x05,01,01,01}));
				tcapcontinue.setApplicationContext(0x04000001003201L);
				tcapcontinue.setProtocolVersion(0x0780);				
				tcapcontinue.setResult(0);
				tcapcontinue.setDialogServiceUser(0);			
				
				
				CamelContinue camelContinue = (CamelContinue)cameldata;
				tcapcontinue.ComponentPortion.addElement(camelContinue.getRootComponent());
				if(logInfoEnabled)Log.info(sessionid+":Sending camelContinue with TCAP Continue Stream");
				SccpHandler.tcapToSccp(sessionid, tcapcontinue, OGT, DGT, 146, 146);
				
				break;
			}
			default:
				break;
			}
		}catch(Exception e){
			Log.warning(sessionid+":Exception Occured :" +e.getClass().getSimpleName()+":"+ Arrays.toString(e.getStackTrace()));

		}
		
	}




	@Override
	public long getNextTransactionID() throws RemoteException {
		
		if (TransactionID<0xffffffff){
			TransactionID++;
		}
		else{
			TransactionID=1;
		}
		
		return TransactionID;
	}

   
	@Override
	public String ping() throws RemoteException {
		// TODO Auto-generated method stub
		return "pong";
	}

	@Override
	public void startLayer() throws Exception {
		initialise();
		establishSccpConnection();
		establishCamelConnection();
		establishMapConnection();
		
	}



	@Override
	public void mapToTcap(long sessionid, GeneralProtocolData mapdata,GeneralProtocolData mapDialogPdu, String OGT, String DGT,long OrigTransactionID, long DestTransactionID)throws RemoteException {
		try{
			TcapBegin tcapbegin = new TcapBegin();		
			tcapbegin.setSourceTransactionID(OrigTransactionID);
			
			TcapContinue tcapcontinue = new TcapContinue();		
			tcapcontinue.setSourceTransactionID(OrigTransactionID);
			tcapcontinue.setDestinationTransactionID(DestTransactionID);
			
			String MapMsgType=mapdata.getClass().getSimpleName();
			
			switch (MapMsgType) {
			case "MapInvokeProcessUSSRequest":
			{
				
			}
			case "MapInvokeUnstructuredSSNotify":
			{
				tcapcontinue.setObjectID((new byte[] {00,0x11,(byte)0x86,0x05,01,01,01}));
				tcapcontinue.setApplicationContext(0x04000001001302L);	
				tcapcontinue.setProtocolVersion(0x0780);				
				tcapcontinue.setResult(0);
				tcapcontinue.setDialogServiceUser(0);		
				
				MapInvokeUnstructuredSSNotify mapUssdNotify = (MapInvokeUnstructuredSSNotify)mapdata;
				tcapcontinue.ComponentPortion.addElement(mapUssdNotify.getRootComponent());
				if(logInfoEnabled)Log.info(sessionid+":Sending USSD Notify with TCAP Continue Stream");
				SccpHandler.tcapToSccp(sessionid, tcapcontinue, OGT, DGT, 147, 6);
				break;
			}
			case "MapInvokeUnstructuredSSRequest":
			{
				tcapcontinue.setApplicationContext(0x04000001001302L);	
				tcapcontinue.setProtocolVersion(0x0780);				
				tcapcontinue.setResult(0);
				tcapcontinue.setDialogServiceUser(0);		
				
				MapInvokeUnstructuredSSRequest mapUssdRequest = (MapInvokeUnstructuredSSRequest)mapdata;
				tcapcontinue.ComponentPortion.addElement(mapUssdRequest.getRootComponent());
				if(logInfoEnabled)Log.info(sessionid+":Sending USSD Request with TCAP Continue Stream");
				SccpHandler.tcapToSccp(sessionid, tcapcontinue, OGT, DGT, 147, 6);
				break;
			}
			case "MapReturnResultUnstructuredSSRequest":
			{
				
			}
			default:
				break;
			}
		}catch(Exception e){
			Log.warning(sessionid+":Exception Occured :" +e.getClass().getSimpleName()+":"+ Arrays.toString(e.getStackTrace()));

		}
		
	}

   
}